/**
 * Copyright 2011 Renato de Jesus Manzoni
 * 
 * SED - Software Engineering and Dependability Research Group
 * 
 *     http://www.sed.ic.unicamp.br/
 * 
 * Distributed Systems Laboratory (LSD) in the Institute of Computing (IC) at University of Campinas (UNICAMP)
 * 
 *     http://www.lsd.ic.unicamp.br/
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package br.unicamp.ic.lsd.wscaa.concurrent;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.cxf.endpoint.ClientCallback;

import br.unicamp.ic.lsd.wscaa.WSCAManager;
import br.unicamp.ic.lsd.wscaa.exception.WSDynamicException;
import br.unicamp.ic.lsd.wscaa.model.ServiceResponse;

/**
 * @author Renato de Jesus Manzoni <rjmanzoni@gmail.com>
 *
 */
public class ServiceResponseCallable implements Callable<ServiceResponse> {

	private final String method;

	private final ClientCallback cb;
	
	//private boolean is = true;
	
	private static Log logger = LogFactory.getLog(ServiceResponseCallable.class);

	public ServiceResponseCallable(String method, ClientCallback cb) {

		this.method = method;
		this.cb = cb;

	}

	//retorna quando tudo da certo! rsrs
	@Override
	public ServiceResponse call() throws Exception {
		try {

			if(logger.isDebugEnabled())
				logger.debug("Getting the result from "+method);
		
//			//TODO espera por resolver as exceptions (ExceptionMonitor?)
//			synchronized (this) {
//				if(logger.isDebugEnabled())
//					logger.debug("Waiting to terminate handling exceptions");
//				
//				this.wait();
//			}
		
			Object[] results = cb.get();
			
			//waitExceptionsHandling();
			
			if(logger.isDebugEnabled())
				logger.debug("The first result from "+method+" is "+results[0]);
			
			return new ServiceResponse(method, results);

		} catch (InterruptedException e) {
			logger.error(e.getLocalizedMessage(), e);
		} catch (ExecutionException e) {
			logger.error("Exception throwed by "+method);
		//	logger.error(e.getLocalizedMessage(), e);
			// TODO WSExceptionFactory precisa ter uma lista com todas as excecoes disponiveis?
			// TODO usar o algoritmo de similaridade verificar as mensagens das excecoes???
			// TODO criar excecoes hash MD5?
			//return new ServiceResponse(method, WSExceptionFactory.createException("Nome"));
			
			waitExceptionsHandling();
			
			return new ServiceResponse(method, new WSDynamicException(e));
		}
		
		return null;
	}
	
	private void waitExceptionsHandling(){
		WSCAManager manager = WSCAManager.getInstance();
		
		if(logger.isTraceEnabled())
			logger.trace("Thread waiting for exception resolution...");
		
		manager.addNotifyMe(this);
		synchronized (this) {
			
		while(!manager.hasDoneExceptionHandling()){
			
			try {
				this.wait();
			} catch (InterruptedException e) {
				logger.error(e.getLocalizedMessage(),e);
			}
		}
		}
		
		if(logger.isTraceEnabled())
			logger.trace("Thread waiting terminated...");
		
	}
}
